package online.heycm.platform.canary.common;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * @author heycm
 * @since 2023/12/30 11:37
 */
public class CanaryHolder {

    private static final int[] X_FLOW_RANGE = new int[]{1, 100};

    private static final Random RANDOM = new Random();

    /**
     * Restful路由匹配
     */
    private static volatile AntPathMatcher pathMatcher;

    private CanaryHolder() {
    }

    public static boolean checkRange(int proportion) {
        return X_FLOW_RANGE[0] <= proportion && proportion <= X_FLOW_RANGE[1];
    }

    /**
     * 流量标记
     *
     * @param proportion 比例
     * @return
     */
    public static boolean markFlow(int proportion) {
        if (!checkRange(proportion)) {
            return false;
        }
        int r = RANDOM.nextInt(X_FLOW_RANGE[1]) + 1;
        return r <= proportion;
    }

    /**
     * 灰度路由匹配
     *
     * @param serviceId 服务id
     * @param path      路由
     * @return
     */
    public static List<CanaryRule> match(String serviceId, String path) {
        if (CanaryRuleCache.rules().isEmpty() || StringUtils.isEmpty(serviceId) || StringUtils.isEmpty(path)) {
            return Collections.emptyList();
        }
        // 精确匹配
        List<CanaryRule> matches = CanaryRuleCache.rules().stream()
                .filter(e -> serviceId.equals(e.getServiceId()) && path.equals(e.getPath()))
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(matches)) {
            return matches;
        }
        // 模式匹配
        matches = CanaryRuleCache.rules().stream()
                .filter(e -> serviceId.equals(e.getServiceId()) && CanaryHolder.patternMatch(e.getPath(), path))
                .collect(Collectors.toList());
        return matches;
    }

    /**
     * Restful路由匹配
     *
     * @param pattern 模板路由
     * @param path    实际路由
     * @return
     */
    private static boolean patternMatch(String pattern, String path) {
        if (pathMatcher == null) {
            synchronized (CanaryRuleCache.class) {
                if (pathMatcher == null) {
                    pathMatcher = new AntPathMatcher();
                }
            }
        }
        return pathMatcher.match(pattern, path);
    }

    /**
     * 获取最高优先级灰度配置
     *
     * @param rules 灰度配置
     * @return
     */
    public static CanaryRule highestPriority(List<CanaryRule> rules) {
        if (rules.isEmpty()) {
            return null;
        }
        return rules.stream().filter(e -> CanaryStrategy.HEAD == CanaryStrategy.ofNullable(e.getCanaryStrategy()))
                .findAny()
                .orElse(rules.get(0));
    }

    /**
     * 获取所有灰度实例 metadata.canary.enable: true
     *
     * @param instances 所有实例
     * @return
     */
    public static List<ServiceInstance> getAllCanaryInstances(List<ServiceInstance> instances) {
        if (CollectionUtils.isEmpty(instances)) {
            return Collections.emptyList();
        }
        return instances.stream().filter(inst -> {
            Map<String, String> metadata = inst.getMetadata();
            if (CollectionUtils.isEmpty(metadata)) {
                return false;
            }
            return CanaryConstant.CANARY_INSTANCE_METADATA[1].equals(metadata.get(CanaryConstant.CANARY_INSTANCE_METADATA[0]));
        }).collect(Collectors.toList());
    }

    /**
     * 获取所有正常实例
     *
     * @param instances 所有实例
     * @return
     */
    public static List<ServiceInstance> getAllNormalInstances(List<ServiceInstance> instances) {
        if (CollectionUtils.isEmpty(instances)) {
            return Collections.emptyList();
        }
        return instances.stream().filter(inst -> {
            Map<String, String> metadata = inst.getMetadata();
            if (CollectionUtils.isEmpty(metadata)) {
                return true;
            }
            return !CanaryConstant.CANARY_INSTANCE_METADATA[1].equals(metadata.get(CanaryConstant.CANARY_INSTANCE_METADATA[0]));
        }).collect(Collectors.toList());
    }
}
